package mn.idax.exchange.otc.web;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import mn.idax.exchange.auth.bean.AuthInfo;
import mn.idax.exchange.auth.util.AuthInfoUtils;
import mn.idax.exchange.common.bean.BaseResponse;
import mn.idax.exchange.common.bean.ResponseData;
import mn.idax.exchange.otc.constant.CommonConstant;
import mn.idax.exchange.otc.constant.RequestUrlConstant;
import mn.idax.exchange.otc.domain.*;
import mn.idax.exchange.otc.entity.OTCAds;
import mn.idax.exchange.otc.entity.OTCOrder;
import mn.idax.exchange.otc.enums.AdEnum;
import mn.idax.exchange.otc.enums.LogOrderProcessEnum;
import mn.idax.exchange.otc.enums.MessageNotifyEnum;
import mn.idax.exchange.otc.enums.OrderState;
import mn.idax.exchange.otc.enums.response.OTCAdResponseEnum;
import mn.idax.exchange.otc.enums.response.OrderResponseEnum;
import mn.idax.exchange.otc.exception.IdaxException;
import mn.idax.exchange.otc.service.CapitalAPIBaseService;
import mn.idax.exchange.otc.service.OTCAdsService;
import mn.idax.exchange.otc.service.OTCOrderService;
import mn.idax.exchange.otc.service.impl.MemoryService;
import mn.idax.exchange.otc.service.impl.RedisService;
import mn.idax.exchange.otc.util.DateUtils;
import mn.idax.exchange.otc.util.LogUtils;
import mn.idax.exchange.otc.util.MessageNotifyUtils;
import mn.idax.exchange.otc.util.ParamUtils;
import mn.idax.exchange.otc.util.function.OrderProcessLogFunction;
import mn.idax.exchange.otc.vo.*;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static mn.idax.exchange.otc.service.OTCThreadPool.THREAD_POOL;

/**
 * Create by jack_huang on 2018/8/8
 */
@Api(value = "订单", tags = {"订单"})
@RestController
@RequestMapping(RequestUrlConstant.MODULE_ORDER)
public class OrderController {

    private static ExecutorService executorService = Executors.newFixedThreadPool(1);

    @Autowired
    private OTCOrderService otcOrderService;

    @Autowired
    private OTCAdsService otcAdsService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private CapitalAPIBaseService capitalAPIBaseService;


    @PostMapping(RequestUrlConstant.ORDER_LIST)
    @ApiOperation(value = "订单列表展示", notes = "需传入查询参数（JSON），(jack_huang，自测通过)")
    public ResponseData getOrderList(@RequestBody OrderPageParamsDTO pageParams) {

        //获取登录用户信息
        AuthInfo authInfo = AuthInfoUtils.getCurrent();
        Integer userId = Optional.ofNullable(authInfo).map(a -> a.getId()).orElse(-1);
        //参数封装
        OrderPageDTO orderPageDTO = makeOrderPageParams(pageParams, userId);
        //查询
        OrderShowResultDTO orderList = new OrderShowResultDTO();
        OrderProcessLogFunction.logOrderProcess(s -> {
            OrderShowResultDTO orderResult = otcOrderService.getOrderPage(orderPageDTO);
            BeanUtils.copyProperties(orderResult, orderList);
        }, this.getClass(), LogOrderProcessEnum.order_query.getMessage());

        return ResponseData.success(orderList);
    }

    /**
     * 功能描述:
     * 订单导出
     *
     * @param: pageParams 查询参数列表
     * @auther: dison
     * @date: 2018/8/9 17:50
     */
    @PostMapping(RequestUrlConstant.ORDER_EXPORT)
    @ApiOperation(value = "订单导出", notes = "说明：<br/>1.需传入查询参数（JSON） <br/>2.导出需用户登录【沈迪雄/自测通过】<br/>3.目前不用")
    public void export(@RequestBody OrderPageParamsDTO pageParams, HttpServletResponse response) throws IOException {
        //获取登录用户信息
        AuthInfo authInfo = AuthInfoUtils.getCurrent();
        Integer userId = Optional.ofNullable(authInfo).map(a -> a.getId()).orElse(-1);
        //参数封装
        OrderPageDTO orderPageDTO = makeOrderPageParams(pageParams, userId);
        // 重置分页数据
        orderPageDTO.setPageIndex(null);
        orderPageDTO.setPageSize(null);
        //查询
        List<OrderExcelDTO> listOrderExcel = otcOrderService.queryExportData(orderPageDTO);
        // 告诉浏览器用什么软件可以打开此文件
        response.setHeader("content-Type", "application/vnd.ms-excel");
        // 下载文件的默认名称
        response.setHeader("Content-Disposition", "attachment;filename=user.xls");
        //编码
        response.setCharacterEncoding("UTF-8");
        Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), OrderExcelDTO.class, listOrderExcel);
        workbook.write(response.getOutputStream());
    }

    @PostMapping(RequestUrlConstant.ORDER_EXPORTMYORDER)
    @ApiOperation(value = "导出我的订单", notes = "说明：<br/>1.需传入查询参数（JSON） <br/>2.导出需用户登录【jack_huang/自测通过】")
    public ResponseData export(@RequestBody OrderPageParamsDTO pageParams) throws IOException {

        //获取登录用户信息
        AuthInfo authInfo = AuthInfoUtils.getCurrent();
        Integer userId = Optional.ofNullable(authInfo).map(a -> a.getId()).orElse(-1);
        //参数封装
        OrderPageDTO orderPageDTO = makeOrderPageParams(pageParams, userId);
        //查询
        List<OrderExcelDTO> exportOrderPage = otcOrderService.queryExportData(orderPageDTO);
        return ResponseData.success(exportOrderPage);
    }

    //封装分页查询参数
    private OrderPageDTO makeOrderPageParams(OrderPageParamsDTO pageParams, Integer userId) {

        Integer pageIndex = pageParams.getPageIndex();
        Integer pageSize = pageParams.getPageSize();

        if (pageIndex == null || pageIndex < 0) {
            pageIndex = 0;
        }
        //防止用户恶意攻击
        if (pageSize == null || pageSize <= 0 || pageSize > 1000) {
            pageSize = 1000;
        }
        String startTime = null;
        String endTime = null;
        /**
         * 最小时间
         */
        if (pageParams.getStartTime() != null) {
            LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(pageParams.getStartTime().getTime()), ZoneId.systemDefault());
            LocalDateTime startOfDay = localDateTime.with(LocalTime.MIN);
            Date startDate = pageParams.getStartTime().from(startOfDay.atZone(ZoneId.systemDefault()).toInstant());
            startTime = DateUtils.getDateToTimeStamp(startDate);
        }
        /**
         * 最大时间
         */
        if (pageParams.getEndTime() != null) {
            LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(pageParams.getEndTime().getTime()), ZoneId.systemDefault());
            LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX);
            Date endDate = pageParams.getEndTime().from(endOfDay.atZone(ZoneId.systemDefault()).toInstant());
            endTime = DateUtils.getDateToTimeStamp(endDate);
        }
        Integer orderState = pageParams.getOrderState();

        String status = null;
        if (orderState == null) {
            orderState = null;
        } else if (orderState == 1) {
            status = CommonConstant.STATE_ONE;
            orderState = 1;
        } else if (orderState == 2) {
            status = CommonConstant.STATE_TWO;
            orderState = 4;
        } else {
            status = CommonConstant.STATE_THREE;
            orderState = 5;
        }
        /***orderType=3 查询所有买卖**/
        if (pageParams.getOrderType() == null || pageParams.getOrderType() == 3) {
            pageParams.setOrderType(null);
        }

        return new OrderPageDTO(userId, pageParams.getOrderNum(), pageParams.getOrderType(), orderState,
                status, pageParams.getPair(), pageIndex, pageSize, startTime, endTime);
    }


    @PostMapping(RequestUrlConstant.ORDER_DETAIL)
    @ApiOperation(value = "查看订单详情", notes = "需传入查询参数（JSON），（jack_huang，自测通过)")
    public ResponseData orderDetail(@RequestBody OrderNumDTO orderNumDTO, HttpServletRequest httpServletRequest) {

        String orderNum = orderNumDTO.getOrderNum();
        if (StringUtils.isEmpty(orderNum)) {
            throw new IdaxException(OrderResponseEnum.ORDERNUM_ISEMPTY.getRespCode());
        }
        //获取登录用户信息
        AuthInfo authInfo = AuthInfoUtils.getCurrent();
        Integer userId = Optional.ofNullable(authInfo).map(a -> a.getId()).orElse(-1);

        Map<String, Object> orderDetails = otcOrderService.getOrderDetails(orderNum, userId, ParamUtils.getRequestSourceCode(httpServletRequest));
        return ResponseData.success(orderDetails);
    }


    @PostMapping(RequestUrlConstant.ORDER_CREATEORDER)
    @ApiOperation(value = "生成订单", notes = "需传入查询参数（JSON），（jack_huang，自测通过)")
    public BaseResponse createOrder(@RequestBody CreateOrderRequest request, HttpServletRequest httpServletRequest) throws Exception {

        //下单开关
        if (Objects.isNull(MemoryService.SYSTEMSETTINGMAP.get(CommonConstant.OTC_CREATEORDER_SWITCH)) ||
                !Boolean.valueOf(MemoryService.SYSTEMSETTINGMAP.get(CommonConstant.OTC_CREATEORDER_SWITCH).toString())) {
            throw new IdaxException(OrderResponseEnum.SYSTEM_MAINTENANCE.getRespCode());
        }

        //获取登录用户信息
        AuthInfo authInfo = AuthInfoUtils.getCurrent();
        Integer userId = Optional.ofNullable(authInfo).map(a -> a.getId()).orElse(-1);
//        Integer userId = 155504;
        //用户被限制作场外交易
        if (redisService.isForbideUser(userId)) {
            throw new IdaxException(OTCAdResponseEnum.USER_IS_FORBIDDEN.getCode());
        }
        //获取广告信息
        Integer adId = request.getAdId();
        if (adId == null) {
            throw new IdaxException(OrderResponseEnum.ORDER_ADIDISEMPTY.getRespCode());
        }

        OTCAds otcAds = otcAdsService.selectByPrimaryKey(adId);
        if (otcAds == null) {
            throw new IdaxException(OTCAdResponseEnum.DATA_NOT_EXIST.getCode());
        }

        GenerateOrderDTO createOrderRequest = checkCreateOrderParams(request, otcAds);


        CreateOrderDTO createOrderDTO = new CreateOrderDTO(createOrderRequest.getAdId(),
                createOrderRequest.getQty(), createOrderRequest.getTotalPrice(), userId, ParamUtils.getRequestSourceCode(httpServletRequest), createOrderRequest.getPrice());
        OTCOrder order = otcOrderService.createOrder(createOrderDTO, otcAds);
        BaseResponse response = null;
        try {
            response = otcOrderService.sendCreateOrderMessage(order);
        } catch (Exception e) {
            LogUtils.warn(this.getClass(), "sendCreateOrderMessage message fail : {}" + ExceptionUtils.getStackTrace(e));
        }
        return response;
    }

    //下单参数校验
    private GenerateOrderDTO checkCreateOrderParams(CreateOrderRequest createOrderRequest, OTCAds otcAds) throws Exception {

        BigDecimal totalPrice = createOrderRequest.getTotalPrice();
        BigDecimal qty = createOrderRequest.getQty();
        if (totalPrice == null || qty == null) {
            throw new IdaxException(OrderResponseEnum.QTYORTOTALMONRY_ISEMPTY.getRespCode());
        }

        if (otcAds.getIsfloating()) {
            //浮动价格广告 始终以单价为准
            FloatingPriceDTO floatingPriceDTO = otcAdsService.floatingAdsPriceConvert(new FloatingPriceDTO(otcAds.getType(), otcAds.getMinprice(), otcAds.getMaxprice(),
                    otcAds.getUnit(), otcAds.getExchange(), otcAds.getPairname(), otcAds.getPrice(), otcAds.getFloatingrate()));
            qty = totalPrice.divide(floatingPriceDTO.getPrice(), 8, BigDecimal.ROUND_DOWN);

            return new GenerateOrderDTO(otcAds.getId(), qty, totalPrice, floatingPriceDTO.getPrice());

        } else {
            //如果广告是买单 买币 数量为准
            if (otcAds.getType().intValue() == AdEnum.type_buy.getCode().intValue()) {
                totalPrice = qty.multiply(otcAds.getPrice()).setScale(2, BigDecimal.ROUND_DOWN);

            } else {
                //如果广告是卖单 卖钱 钱为准
                qty = totalPrice.divide(otcAds.getPrice(), 8, BigDecimal.ROUND_DOWN);
            }
        }
        //精度处理-很重要
        qty = qty.divide(BigDecimal.ONE, 8, BigDecimal.ROUND_DOWN);
        totalPrice = totalPrice.divide(BigDecimal.ONE, 2, BigDecimal.ROUND_DOWN);

        return new GenerateOrderDTO(otcAds.getId(), qty, totalPrice, otcAds.getPrice());
    }

    /**
     * 标记付款已完成
     *
     * @param
     * @return
     */
    @PostMapping(RequestUrlConstant.ORDER_CONFIRMPAID)
    @ApiOperation(value = "买家标记付款已完成", notes = "买家已付款，需传入查询参数（JSON）,jack_huang，自测通过）")
    public ResponseData confirmPaid(@RequestBody ConfirmPaidDTO confirmPaidDTO) {

        String orderNum = confirmPaidDTO.getOrderNum();
        Integer payMethod = confirmPaidDTO.getPayMethod();
        if (StringUtils.isEmpty(orderNum)) {
            throw new IdaxException(OrderResponseEnum.ORDERNUM_ISEMPTY.getRespCode());
        }
        if (payMethod == null) {
            throw new IdaxException(OrderResponseEnum.PAY_METHOD_ISEMPTY.getRespCode());
        }

        //获取登录用户信息
        AuthInfo authInfo = AuthInfoUtils.getCurrent();
        Integer userId = Optional.ofNullable(authInfo).map(a -> a.getId()).orElse(-1);
//        Integer userId = 155504;
        if (!otcOrderService.confirmPaid(orderNum, payMethod, userId)) {
            throw new IdaxException(OrderResponseEnum.ORDER_CONFIRMPAIDFAIL.getRespCode());
        }
        return ResponseData.success();
    }


    public OTCOrder checkOrderExist(String orderNum) {
        if (StringUtils.isEmpty(orderNum)) {
            throw new IdaxException(OrderResponseEnum.ORDERNUM_ISEMPTY.getRespCode());
        }

        OTCOrder otcOrder = otcOrderService.getOrderByOrderNum(orderNum);

        if (otcOrder == null) {
            throw new IdaxException(OrderResponseEnum.ORDER_ISNOTEXIST.getRespCode());
        }
        return otcOrder;
    }

    @PostMapping(RequestUrlConstant.ORDER_RELEASE)
    @ApiOperation(value = "确认放行(订单完成)", notes = "（沈迪雄自测通过）")
    public BaseResponse release(@RequestBody OrderNumDTO orderNumDTO) {

        //下单开关
        if (Objects.isNull(MemoryService.SYSTEMSETTINGMAP.get(CommonConstant.OTC_CREATEORDER_SWITCH)) ||
                !Boolean.valueOf(MemoryService.SYSTEMSETTINGMAP.get(CommonConstant.OTC_CREATEORDER_SWITCH).toString())) {
            throw new IdaxException(OrderResponseEnum.SYSTEM_MAINTENANCE.getRespCode());
        }

        AuthInfo authInfo = AuthInfoUtils.getCurrent();
        Integer userId = Optional.ofNullable(authInfo).map(a -> a.getId()).orElse(-1);
        OTCOrder otcOrder = checkOrderExist(orderNumDTO.getOrderNum());

        otcOrderService.releaseConin(otcOrder, userId);

        THREAD_POOL.execute(() -> {

            try {
                // 发送通知
                otcOrderService.pushOrderStateMessage(otcOrder, OrderState.STATE_FINISH.getCode(), otcOrder.getSeller());

                // 发送我的通知消息
                MessageNotifyUtils.sendNotify(otcOrder.getBuyer(),
                        otcOrder.getNumber(),
                        MessageNotifyEnum.BodyTemplate.order_release,
                        MessageNotifyUtils.getNotifyNickName(otcOrder.getSeller()));
                otcOrderService.sendMessageAtRelease(otcOrder);
            } catch (Exception e) {
                LogUtils.error(this.getClass(), "messagePutError at " + OrderState.STATE_TORELEASED.getType());
            }

            //后置事务
            otcOrderService.releasePostProcess(otcOrder);
        });

        return ResponseData.success();
    }


    @PostMapping(RequestUrlConstant.ORDER_CANCELORDER)
    @ApiOperation(value = "取消订单", notes = "只有付钱的一方可以取消订单（jack_huang，自测通过）")
    public ResponseData cancelOrder(@RequestBody OrderNumDTO orderNumDTO) {

        //撤单开关
        if (Objects.isNull(MemoryService.SYSTEMSETTINGMAP.get(CommonConstant.OTC_CANCELORDER_SWITCH)) ||
                !Boolean.valueOf(MemoryService.SYSTEMSETTINGMAP.get(CommonConstant.OTC_CANCELORDER_SWITCH).toString())) {
            throw new IdaxException(OrderResponseEnum.SYSTEM_MAINTENANCE.getRespCode());
        }

        AuthInfo authInfo = AuthInfoUtils.getCurrent();
        Integer userId = Optional.ofNullable(authInfo).map(a -> a.getId()).orElse(-1);

        OTCOrder otcOrder = checkOrderExist(orderNumDTO.getOrderNum());

        otcOrderService.cancelOrder(otcOrder, userId);
        try {
            //发送消息
            otcOrderService.pushOrderStateMessage(otcOrder, OrderState.STATE_BUYER_CANCEL.getCode(), otcOrder.getBuyer());
            // 发送我的通知消息
            MessageNotifyUtils.sendNotify(otcOrder.getSeller(),
                    otcOrder.getNumber(),
                    MessageNotifyEnum.BodyTemplate.order_cancel,
                    MessageNotifyUtils.getNotifyNickName(userId));
        } catch (Exception e) {
            LogUtils.error(this.getClass(), "messagePutError at " + OrderState.STATE_BUYER_CANCEL.getType());
        }


        return ResponseData.success();
    }

    @PostMapping(RequestUrlConstant.ORDER_LIST_TRADE_RECORD)
    @ApiOperation(value = "查询累计交易记录", notes = "累计交易记录交易成功的-包含买卖（shendx，自测通过）")
    public ResponseData getTradeRecord(@RequestBody TradeRecordDTO tradeRecordDTO) {
        AuthInfo authInfo = AuthInfoUtils.getCurrent();
        Integer userId = Optional.ofNullable(authInfo).map(a -> a.getId()).orElse(-1);
        tradeRecordDTO.setUserId(userId);

        PageVo<TradeRecordVO> pageVo = this.otcOrderService.listTradeRecord(tradeRecordDTO);
        return ResponseData.success(pageVo);
    }

}
